﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml.Linq;
using System.Drawing.Printing;
using System.IO;

namespace Light.Utility
{

    /// <summary>
    /// 绘制（文字，图片，直线）工具类
    /// </summary>
    public static class DrawHelper
    {

        /// <summary>
        /// 根据XML文件中绘制
        /// </summary>
        /// <param name="graphics">画板</param>
        /// <param name="xmlFilePath">xml模板文件路径</param>
        public static void Draw(Graphics graphics, string xmlFilePath)
        {
            List<DrawItem> items = GetDrawItem(xmlFilePath);
            Draw(graphics, items);
        }

        /// <summary>
        /// 从XML文件中读取绘制项 (XML文件数据格式参照 DrawTemplate.xml)
        /// </summary>
        /// <param name="xmlFilePath">xml模板文件路径</param>
        /// <returns></returns>
        public static List<DrawItem> GetDrawItem(string xmlFilePath)
        {
            XDocument doc = XDocument.Load(xmlFilePath);
            return GetDrawItem(doc);
        }

        /// <summary>
        /// 根据XML字符串绘制
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="xmlString"></param>
        public static void DrawFromXmlString(Graphics graphics, string xmlString)
        {

            List<DrawItem> items = GetDrawItemFromXmlString(xmlString);
            Draw(graphics, items);
        }

        /// <summary>
        /// 从XML字符串中读取绘制项 (XML字符串数据格式参照 DrawTemplate.xml)
        /// </summary>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static List<DrawItem> GetDrawItemFromXmlString(string xmlString)
        {
            XDocument doc = XDocument.Parse(xmlString);
            return GetDrawItem(doc);
        }

        /// <summary>
        /// 获取要绘制的项
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        private static List<DrawItem> GetDrawItem(XDocument doc)
        {
            List<DrawItem> printItems = new List<DrawItem>();
            DrawPage page = GetDrawPage(doc);
            printItems.Add(page);

            XElement root = doc.Document.Element("PrintMode");
            IEnumerable<XElement> items = root.Elements();

            foreach (XElement item in items)
            {
                string drawType = XmlHelper.GetAttributeValue(item, "Type");

                if (drawType == "Static")
                {
                    DrawText pi = new DrawText();
                    pi.Text = XmlHelper.GetAttributeValue(item, "Text");

                    string[] size = XmlHelper.GetAttributeValue(item, "Size").Split(',');
                    if (size.Length == 2)
                        pi.Size = new Size(int.Parse(size[0]), int.Parse(size[1]));

                    string[] location = XmlHelper.GetAttributeValue(item, "Location").Split(',');
                    if (location.Length == 2)
                        pi.Location = new Point(int.Parse(location[0]), int.Parse(location[1]));
                    //pi.Location = new Point(int.Parse(location[0]) + page.Location.X, int.Parse(location[1]) + page.Location.Y);

                    string[] color = XmlHelper.GetAttributeValue(item, "Color").Split(',');
                    if (color.Length == 3)
                        pi.Color = Color.FromArgb(int.Parse(color[0]), int.Parse(color[1]), int.Parse(color[2]));


                    //Font("字体名,字号,是否加粗,是否倾斜,是否加下划线")
                    string[] font = XmlHelper.GetAttributeValue(item, "Font").Split(',');
                    FontStyle fontStyle = FontStyle.Regular;

                    if (font.Length > 2 && font[2] == "1")
                    {
                        fontStyle = fontStyle | FontStyle.Bold;
                    }
                    if (font.Length > 3 && font[3] == "1")
                    {
                        fontStyle = fontStyle | FontStyle.Italic;
                    }
                    if (font.Length > 4 && font[4] == "1")
                    {
                        fontStyle = fontStyle | FontStyle.Underline;
                    }

                    pi.Font = new Font(font[0], float.Parse(font[1]), fontStyle);

                    printItems.Add(pi);
                }
                else if (drawType == "Line")
                {
                    DrawLine pi = new DrawLine();

                    string[] start = XmlHelper.GetAttributeValue(item, "Point1").Split(',');
                    if (start.Length == 2)
                        pi.Point1 = new Point(int.Parse(start[0]), int.Parse(start[1]));
                    //pi.Point1 = new Point(int.Parse(start[0]) + page.Location.X, int.Parse(start[1]) + page.Location.Y);

                    string[] end = XmlHelper.GetAttributeValue(item, "Point2").Split(',');
                    if (end.Length == 2)
                        pi.Point2 = new Point(int.Parse(end[0]), int.Parse(end[1]));
                    //pi.Point2 = new Point(int.Parse(end[0]) + page.Location.X, int.Parse(end[1]) + page.Location.Y);

                    string[] color = XmlHelper.GetAttributeValue(item, "Color").Split(',');
                    if (color.Length == 3)
                        pi.Color = Color.FromArgb(int.Parse(color[0]), int.Parse(color[1]), int.Parse(color[2]));

                    pi.Width = XmlHelper.GetAttributeValue(item, "Width", 1);

                    printItems.Add(pi);
                }
                else if (drawType == "Image")
                {
                    DrawImage pi = new DrawImage();

                    string[] location = XmlHelper.GetAttributeValue(item, "Location").Split(',');
                    pi.Location = new Point(int.Parse(location[0]), int.Parse(location[1]));
                    //pi.Location = new Point(int.Parse(location[0]) + page.Location.X, int.Parse(location[1]) + page.Location.Y);

                    string src = XmlHelper.GetAttributeValue(item, "Src");
                    pi.Image = Image.FromFile(src);

                    printItems.Add(pi);
                }
            }

            return printItems;
        }

        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="items"></param>
        public static void Draw(Graphics graphics, List<DrawItem> items)
        {
            foreach (DrawItem item in items)
            {
                if (item.Type == DrawItemType.Text)
                {
                    DrawText pi = item as DrawText;
                    graphics.DrawString(pi.Text, pi.Font, new SolidBrush(pi.Color), pi.Location);
                }
                else if (item.Type == DrawItemType.Line)
                {
                    DrawLine pi = item as DrawLine;
                    graphics.DrawLine(new Pen(new SolidBrush(pi.Color), pi.Width), pi.Point1, pi.Point2);
                }
                else if (item.Type == DrawItemType.Image)
                {
                    DrawImage pi = item as DrawImage;
                    graphics.DrawImage(pi.Image, pi.Location);
                }
            }
        }


        /// <summary>
        /// 获取绘制页面
        /// </summary>
        /// <param name="xmlString">xml模板字符串</param>
        /// <returns></returns>
        public static DrawPage GetDrawPageFromXmlString(string xmlString)
        {
            XDocument doc = XDocument.Parse(xmlString);
            return GetDrawPage(doc);
        }

        /// <summary>
        /// 获取绘制页面
        /// </summary>
        /// <param name="xmlFilePath">xml模板文件路径</param>
        /// <returns></returns>
        public static DrawPage GetDrawPage(string xmlFilePath)
        {
            XDocument doc = XDocument.Load(xmlFilePath);
            return GetDrawPage(doc);
        }



        /// <summary>
        /// 将对象转化成xml字符串
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        public static string GetXmlString(params DrawItem[] items)
        {
            StringBuilder builder = new StringBuilder();

            builder.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            builder.Append("\r\n");
            builder.Append("<PrintMode Version=\"1.0\">");
            builder.Append("\r\n");

            foreach (var item in items)
            {
                if (item is DrawPage)
                {
                    DrawPage page = item as DrawPage;
                    builder.Append(string.Format("<Item Type=\"Page\" Location=\"{0},{1}\" Size=\"{2},{3}\" Margins=\"{4},{5},{6},{7}\" Landscape=\"{8}\" Font=\"{9},{10},{11},{12},{13}\" PaperName=\"{14}\"  />", page.Location.X, page.Location.Y, page.Size.Width, page.Size.Height, page.Margins.Left, page.Margins.Right, page.Margins.Top, page.Margins.Bottom, page.Landscape.ToString(), page.Font.Name, page.Font.Bold ? 1 : 0, page.Font.Italic ? 1 : 0, page.Font.Underline ? 1 : 0, page.Font.Strikeout ? 1 : 0, page.PaperName));
                    builder.Append("\r\n");

                }
                else if (item is DrawText)
                {
                    DrawText text = item as DrawText;
                    builder.Append(string.Format("<Item Type=\"Static\" Location=\"{0},{1}\" Font=\"{2},{3},{4},{5},{6}\" Text=\"{7}\" Color=\"{8},{9},{10}\" Size=\"{11},{12}\" />", text.Location.X, text.Location.Y, text.Font.Name, text.Font.Size, text.Font.Bold ? 1 : 0, text.Font.Italic ? 1 : 0, text.Font.Underline ? 1 : 0, text.Text, text.Color.R, text.Color.G, text.Color.B, text.Size.Width, text.Size.Height));
                    builder.Append("\r\n");

                }
                else if (item is DrawImage)
                {
                    DrawImage image = item as DrawImage;
                    builder.Append(string.Format("<Item Type=\"Image\" Location=\"{0},{1}\" Src=\"{2}}\" />", image.Location.X, image.Location.Y, image.Image.ToString()));
                    builder.Append("\r\n");
                }
                else if (item is DrawLine)
                {
                    DrawLine line = item as DrawLine;
                    builder.Append(string.Format("<Item Type=\"Line\" Point1=\"{0},{1}\" Point2=\"{2},{3}\" Color=\"{4},{5},{6}\" Width=\"{7}\" />", line.Point1.X, line.Point1.Y, line.Point2.X, line.Point2.Y, line.Color.R, line.Color.G, line.Color.B, line.Width));
                    builder.Append("\r\n");
                }
            }
            builder.Append("</PrintMode>");

            return builder.ToString();
        }


        /// <summary>
        /// 保存至文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="items"></param>
        public static void SaveToFile(string path, params DrawItem[] items)
        {
            File.WriteAllText(path, GetXmlString(items));
        }

        private static DrawPage GetDrawPage(XDocument doc)
        {
            DrawPage page = new DrawPage();

            try
            {
                XElement node = doc.Document.Element("PrintMode").Elements().SingleOrDefault(p => p.Attribute("Type").Value == "Page");

                string[] location = XmlHelper.GetAttributeValue(node, "Location").Split(',');
                if (location.Length == 2)
                    page.Location = new Point(int.Parse(location[0]), int.Parse(location[1]));

                string[] size = XmlHelper.GetAttributeValue(node, "Size").Split(',');
                if (size.Length == 2)
                    page.Size = new Size(int.Parse(size[0]), int.Parse(size[1]));

                string[] margins = XmlHelper.GetAttributeValue(node, "Margins").Split(',');
                if (margins.Length == 4)
                    page.Margins = new Margins(int.Parse(margins[0]), int.Parse(margins[1]), int.Parse(margins[2]), int.Parse(margins[3]));
                page.PaperName = XmlHelper.GetAttributeValue(node, "PaperName", "A4");

                page.Landscape = XmlHelper.GetAttributeValue(node, "Landscape", false);

            }
            catch (Exception ex)
            {
                //throw new Exception("模板格式不正确，请确保只有一个页面配置项！");
            }
            return page;
        }

    }

    /// <summary>
    /// 绘制项
    /// </summary>
    public class DrawItem
    {
        /// <summary>
        /// 类别
        /// </summary>
        public DrawItemType Type { get; set; }
    }

    /// <summary>
    /// 绘制文本项
    /// Xml格式示例：Item Type="Static" Name="Label1" Text="用户名称" TextDirection="0" Font="宋体,14,0,0,0" Location="69,29" Size="85,23" 
    /// </summary>
    public class DrawText : DrawItem
    {

        public DrawText()
        {
            Type = DrawItemType.Text;
            Color = Color.Black;
            Size = new Size(80, 26);
            this.Font = new Font("宋体", 12);
        }

        /// <summary>
        /// 文本内容
        /// </summary>
        public string Text { get; set; }

        /// <summary>
        /// 字体
        /// </summary>
        public Font Font { get; set; }

        /// <summary>
        /// 画笔
        /// </summary>
        public Color Color { get; set; }

        /// <summary>
        /// 大小
        /// </summary>
        public Size Size { get; set; }

        /// <summary>
        /// 起点位置
        /// </summary>
        public Point Location { get; set; }
    }

    /// <summary>
    /// 绘制直线项
    /// Xml格式示例：Item Type="Line" Name="FormBack" Point1="42,60" Point2="542,60" 
    /// </summary>
    public class DrawLine : DrawItem
    {

        public DrawLine()
        {
            Type = DrawItemType.Line;
            Color = Color.Black;
            Width = 1;
        }

        /// <summary>
        /// 第一个点
        /// </summary>
        public Point Point1 { get; set; }

        /// <summary>
        /// 第二个点
        /// </summary>
        public Point Point2 { get; set; }

        /// <summary>
        /// 颜色
        /// </summary>
        public Color Color { get; set; }

        /// <summary>
        /// 宽度
        /// </summary>
        public float Width { get; set; }

    }

    /// <summary>
    /// 绘制图片项
    ///Xml格式示例：Item Type="Image" Name="FormBack" Location="0,0" Src="./1000.jpg"
    /// </summary>
    public class DrawImage : DrawItem
    {
        public DrawImage()
        {
            Type = DrawItemType.Image;
        }

        /// <summary>
        /// 图片
        /// </summary>
        public Image Image { get; set; }


        /// <summary>
        /// 起点位置
        /// </summary>
        public Point Location { get; set; }

    }

    /// <summary>
    /// 绘制页,一个画板中只能有一个DrawPage
    /// Xml格式示例：Item Type="Page" Name="FormBack" Location="10,10" Size="500,500"
    /// </summary>
    public class DrawPage : DrawItem
    {
        /// <summary>
        /// 默认位置为（0，0）
        /// </summary>
        public DrawPage()
        {
            Type = DrawItemType.Page;
            this.Font = new Font("宋体", 12);
            Location = new Point(0, 0);
            Margins = new Margins(0, 0, 0, 0);
            PaperName = "A4";
        }

        public string PaperName { get; set; }

        /// <summary>
        /// 字体
        /// </summary>
        public Font Font { get; set; }

        /// <summary>
        /// 起点位置
        /// </summary>
        public Point Location { get; set; }

        /// <summary>
        /// 页面大小
        /// </summary>
        public Size Size { get; set; }

        /// <summary>
        /// 边距
        /// </summary>
        public Margins Margins { get; set; }

        /// <summary>
        /// 是否横向打印
        /// </summary>
        public bool Landscape { get; set; }

    }

    /// <summary>
    /// 绘制项类别
    /// </summary>
    public enum DrawItemType
    {
        /// <summary>
        /// 普通静态文字
        /// </summary>
        Text,
        /// <summary>
        /// 直线
        /// </summary>
        Line,
        /// <summary>
        /// 图片
        /// </summary>
        Image,

        /// <summary>
        /// 页面，页面中的元素位置以页面起始位置基准
        /// </summary>
        Page,
    }
}
